package com.yunli.mall.common.util;

import com.yunli.mall.common.schema.BaseEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.core.Converter;

import java.util.Arrays;
import java.util.Objects;

/**
 * @author wangyue
 * @description 方便在steam().map().collect()中进行类型转换使用
 * @date 2020-01-16 15:15
 */
@Slf4j
public class BeanCopyUtil {

    /**
     * @param source      源数据
     * @param targetClass 目标类型
     * @param converter   转换器
     * @return
     */
    public static <T> T copy(Object source, Class<T> targetClass, Converter converter) {
        boolean useConverter = null != converter;
        try {
            if(Objects.isNull(source)){
                return null;
            }
            T t = targetClass.newInstance();
            // 用Spring的BeanCopier
            BeanCopier.create(source.getClass(), targetClass, useConverter).copy(source, t, converter);
            return t;
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @param source
     * @param targetClass
     * @param <T>
     * @return
     */
    public static <T> T copy(Object source, Class<T> targetClass) {
        try {
            if(Objects.isNull(source)){
                return null;
            }
            T t = targetClass.newInstance();
            // 用Spring的BeanCopier
            BeanCopier.create(source.getClass(), targetClass, false).copy(source, t, null);
            return t;
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 自定义Converter,添加基于BaseEnum的枚举转换
     *
     * @return
     */
    public static Converter customConverter() {
        return (o, aClass, o1) -> {
            if (Objects.isNull(o)) {
                return null;
            }
            if (o.getClass().equals(aClass)) {
                return o;
            }
            // source是枚举的情况
            if (o instanceof BaseEnum) {
                // 目标是Integer的取code
                if (Integer.class.equals(aClass)) {
                    return ((BaseEnum) o).getCode();
                }
                // 目标是String的取desc,如果没有取枚举的name
                if (String.class.equals(aClass)) {
                    return (null != ((BaseEnum) o).getDesc()) ? ((BaseEnum) o).getDesc() : o.toString();
                }
            }
            // target是枚举的情况
            if (aClass.isEnum() && Arrays.asList(aClass.getGenericInterfaces()).contains(BaseEnum.class)) {
                // source是Integer的根据code转枚举
                if (o instanceof Integer) {
                    return BaseEnum.convertCode2Enum(aClass, (Integer) o);
                }
                // source是String的根据desc转枚举
                if (o instanceof String) {
                    return BaseEnum.convertDesc2Enum(aClass, (String) o);
                }
            }
            if (log.isWarnEnabled()) {
                log.warn("customConverter 未处理的值:{}, Class:{}, 方法:{}", o, aClass.toString(), o1);
            }
            return null;
        };
    }

}
